package com.atguigu.gmall.index.config;

import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.index.feign.PmsClient;
import com.atguigu.gmall.pms.entity.CategoryEntity;
import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.List;

@Configuration
public class RedisCacheConfig {
    @Autowired
    PmsClient pmsClient;
    //初始化redisson的客户端对象注入到容器中
    //通过客户端对象可以创建 Redisson中其他的工具类对象
    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
//        config.setLockWatchdogTimeout() 设置看门狗的执行续期的时间  默认30秒
        config.useSingleServer() //单节点
                .setAddress("redis://192.168.1.170:6379");
        RedissonClient redissonClient = Redisson.create(config);
        //1初始化信号量
        RSemaphore sempahore = redissonClient.getSemaphore("sempahore");
        //设置资源数量
        sempahore.trySetPermits(1);
        //2 初始化闭锁
        RCountDownLatch cdl = redissonClient.getCountDownLatch("cdl");
        cdl.trySetCount(1);

        //3 初始化布隆过滤器
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloom:cates");
        //cid查询它的二级分类： cid必须存在 并且它有二级分类集合  这个cid就有数据
        // 项目启动时 可以将存在并且有二级分类的cid存入到布隆过滤器中
        //1、查询所有的一级分类id
        ResponseVo<List<CategoryEntity>> responseVo = pmsClient.parent("0");
        if(!CollectionUtils.isEmpty(responseVo.getData())){
            bloomFilter.tryInit(responseVo.getData().size()+100,0.03);
            //查询每个一级分类的二级分类，如果有一级分类id则存入到布隆过滤器
            List<CategoryEntity> pcates = responseVo.getData();
            for (CategoryEntity pcate : pcates) {
                ResponseVo<List<CategoryEntity>> listResponseVo = pmsClient.lv2AndSubsCates(pcate.getId() + "");
                if(!CollectionUtils.isEmpty(listResponseVo.getData())){
                    bloomFilter.add(pcate.getId()+"");
                }

            }

        }

        return redissonClient;
    }


    //1、RedisTemplate配置键和值的序列化器
    @Autowired
    RedisTemplate redisTemplate;
    @PostConstruct
    public void init(){
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    }

    //2、缓存管理CacheManager接口的实现
    //LettuceConnectionFactory commons-pool2包中提供的Redis连接池工厂类
    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory connectionFactory){
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30)) //缓存过期时间
                .disableCachingNullValues() //不缓存空值
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new StringRedisSerializer())) //键序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new GenericJackson2JsonRedisSerializer()));//值序列化器
        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
                    .cacheDefaults(cacheConfig).build();
        return cacheManager;
    }
}
